package com.ruoyi.file.service;

import java.io.InputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.nacos.common.utils.IoUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.file.FileTypeUtils;
import com.ruoyi.common.core.utils.file.MimeTypeUtils;
import com.ruoyi.common.core.exception.file.FileSizeLimitExceededException;
import com.ruoyi.common.core.exception.file.InvalidExtensionException;
import com.ruoyi.file.config.MinioConfig;
import com.ruoyi.file.utils.FileUploadUtils;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import java.util.concurrent.CompletableFuture;

/**
 * Minio 文件存储
 *
 * @author ruoyi
 */
@Primary
@Service
public class MinioSysFileServiceImpl implements ISysFileService
{
    @Autowired
    private MinioConfig minioConfig;

    @Autowired
    private MinioClient client;
    
    @Autowired
    private VideoOptimizationService videoOptimizationService;

    /**
     * Minio文件上传接口
     *
     * @param file 上传的文件
     * @return 访问地址
     * @throws Exception
     */
    @Override
    public String uploadFile(MultipartFile file) throws Exception
    {
        InputStream inputStream = null;
        try
        {
            // 验证文件
            validateFile(file);
            
            String fileName = FileUploadUtils.extractFilename(file);
            inputStream = file.getInputStream();
            
            // 根据文件类型设置合适的Content-Type
            String contentType = getContentType(file);
            
            // 检查存储桶是否存在，不存在则创建
            ensureBucketExists();
            
            PutObjectArgs args = PutObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object(fileName)
                    .stream(inputStream, file.getSize(), -1)
                    .contentType(contentType)
                    .build();
            client.putObject(args);
            return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
        }
        catch (Exception e)
        {
            // 提供更详细的错误信息
            String errorMsg = "MinIO文件上传失败: " + e.getMessage();
            if (e.getMessage().contains("Connection refused")) {
                errorMsg = "MinIO服务连接失败，请检查MinIO服务是否启动";
            } else if (e.getMessage().contains("Access Denied")) {
                errorMsg = "MinIO访问权限不足，请检查访问密钥配置";
            } else if (e.getMessage().contains("No such bucket")) {
                errorMsg = "MinIO存储桶不存在，请检查存储桶配置";
            }
            throw new RuntimeException(errorMsg, e);
        }
        finally
        {
            IoUtils.closeQuietly(inputStream);
        }
    }
    
    /**
     * Minio视频文件上传接口
     *
     * @param file 上传的视频文件
     * @return 访问地址
     * @throws Exception
     */
    public String uploadVideoFile(MultipartFile file) throws Exception
    {
        InputStream inputStream = null;
        try
        {
            // 验证视频文件
            FileUploadUtils.assertVideoAllowed(file);
            
            String fileName = FileUploadUtils.extractFilename(file);
            inputStream = file.getInputStream();
            
            // 设置视频文件的Content-Type
            String contentType = getVideoContentType(file);
            
            // 检查存储桶是否存在，不存在则创建
            ensureBucketExists();
            
            PutObjectArgs args = PutObjectArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .object("videos/" + fileName)  // 视频文件放在videos目录下
                    .stream(inputStream, file.getSize(), -1)
                    .contentType(contentType)
                    .build();
            client.putObject(args);
            
            String originalUrl = minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/videos/" + fileName;
            
            // 异步启动视频优化
            CompletableFuture<String> optimizationFuture = videoOptimizationService.optimizeVideoAsync(file, originalUrl);
            
            // 记录优化任务，但不等待完成
            optimizationFuture.thenAccept(optimizedUrl -> {
                if (!optimizedUrl.equals(originalUrl)) {
                    // 这里可以更新数据库中的视频URL，或者发送通知
                    // 暂时只记录日志
                    System.out.println("视频优化完成，新URL: " + optimizedUrl);
                }
            }).exceptionally(throwable -> {
                System.err.println("视频优化失败: " + throwable.getMessage());
                return null;
            });
            
            return originalUrl;
        }
        catch (Exception e)
        {
            // 提供更详细的错误信息
            String errorMsg = "MinIO视频文件上传失败: " + e.getMessage();
            if (e.getMessage().contains("Connection refused")) {
                errorMsg = "MinIO服务连接失败，请检查MinIO服务是否启动";
            } else if (e.getMessage().contains("Access Denied")) {
                errorMsg = "MinIO访问权限不足，请检查访问密钥配置";
            } else if (e.getMessage().contains("No such bucket")) {
                errorMsg = "MinIO存储桶不存在，请检查存储桶配置";
            }
            throw new RuntimeException(errorMsg, e);
        }
        finally
        {
            IoUtils.closeQuietly(inputStream);
        }
    }
    
    /**
     * 获取文件的Content-Type
     */
    private String getContentType(MultipartFile file)
    {
        String extension = FileTypeUtils.getExtension(file);
        switch (extension.toLowerCase())
        {
            case "mp4":
                return "video/mp4";
            case "avi":
                return "video/x-msvideo";
            case "mov":
                return "video/quicktime";
            case "wmv":
                return "video/x-ms-wmv";
            case "flv":
                return "video/x-flv";
            case "webm":
                return "video/webm";
            case "mkv":
                return "video/x-matroska";
            case "m4v":
                return "video/x-m4v";
            case "3gp":
                return "video/3gpp";
            case "ogv":
                return "video/ogg";
            default:
                return file.getContentType() != null ? file.getContentType() : "application/octet-stream";
        }
    }
    
    /**
     * 获取视频文件的Content-Type
     */
    private String getVideoContentType(MultipartFile file)
    {
        return getContentType(file);
    }

    /**
     * Minio文件删除接口
     * 
     * @param fileUrl 文件访问URL
     * @throws Exception
     */
    @Override
    public void deleteFile(String fileUrl) throws Exception
    {
        try
        {
            String minioFile = StringUtils.substringAfter(fileUrl, minioConfig.getBucketName());
            client.removeObject(RemoveObjectArgs.builder().bucket(minioConfig.getBucketName()).object(minioFile).build());
        }
        catch (Exception e)
        {
            throw new RuntimeException("Minio Failed to delete file", e);
        }
    }
    
    /**
     * 验证文件
     */
    private void validateFile(MultipartFile file) throws FileSizeLimitExceededException, InvalidExtensionException
    {
        if (file == null || file.isEmpty()) {
            throw new RuntimeException("上传文件不能为空");
        }
        
        // 检查文件大小
        long size = file.getSize();
        if (size > FileUploadUtils.DEFAULT_MAX_SIZE) {
            throw new FileSizeLimitExceededException(FileUploadUtils.DEFAULT_MAX_SIZE / 1024 / 1024);
        }
        
        // 检查文件扩展名
        String extension = FileTypeUtils.getExtension(file);
        if (!isAllowedImageExtension(extension)) {
            throw new InvalidExtensionException.InvalidImageExtensionException(
                MimeTypeUtils.IMAGE_EXTENSION, extension, file.getOriginalFilename());
        }
    }
    
    /**
     * 检查是否为允许的图片扩展名
     */
    private boolean isAllowedImageExtension(String extension) {
        String[] allowedExtensions = {"jpg", "jpeg", "png", "gif", "bmp", "webp"};
        for (String allowed : allowedExtensions) {
            if (allowed.equalsIgnoreCase(extension)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 确保存储桶存在
     */
    private void ensureBucketExists() throws Exception {
        try {
            boolean exists = client.bucketExists(BucketExistsArgs.builder()
                .bucket(minioConfig.getBucketName())
                .build());
            
            if (!exists) {
                client.makeBucket(MakeBucketArgs.builder()
                    .bucket(minioConfig.getBucketName())
                    .build());
            }
        } catch (Exception e) {
            throw new RuntimeException("检查或创建MinIO存储桶失败: " + e.getMessage(), e);
        }
    }
}
